import pandas as pd
from utils.common import get_holidays, get_current_time_type, fea_div_v2, get_days_inter, find_max_consecutive


def get_bill_data(df,
                  current_apply_time):
    bill_status = df['status']
    repaid_principal = df['repaid_principal']
    repaid_interest = df['repaid_interest']
    repaid_cut_interest = df['repaid_cut_interest']
    repaid_service_fee = df['repaid_service_fee']
    repaid_management_fee = df['repaid_management_fee']
    repaid_overdue_interest = df['repaid_overdue_interest']
    repaid_penalty = df['repaid_penalty']
    discount_amount = df['discount_amount']
    waive_amount = df['waive_amount']
    payoff_time = df['update_time']
    repayment_date = df['repayment_date']
    settlement_type = df['settlement_type']
    extension_count = df['extension_count']
    interest = df['interest']
    ovd_days = 0
    bill_category = ''
    # 对于未还清的订单,判断是逾期在贷还是未到还款日当前在贷
    if bill_status == 1 and extension_count == 0 and settlement_type != 2:
        if current_apply_time[:10] > repayment_date:
            bill_category = 'ovd_onloan'  # 逾期在贷
            ovd_days = get_days_inter(current_apply_time, repayment_date + ' 00:00:00')
        else:
            bill_category = 'onloan'  # 未到还款日的在贷
            ovd_days = 0
    if bill_status == 2 and extension_count == 0 and settlement_type != 2:  # 对于已经还清的账单，计算还清时间与回溯时间的差距 重新计算逻辑
        if current_apply_time >= payoff_time:  # 对于还清的账单判断还清类型
            ovd_days = get_days_inter(payoff_time, repayment_date + ' 00:00:00')
            if ovd_days == 0:
                bill_category = 'normal_payoff'  # 正常结清
            elif ovd_days > 0:
                bill_category = 'ovd_payoff'  # 逾期结清
            elif ovd_days < 0:
                bill_category = 'pre_payoff'  # 提前还清
        elif current_apply_time < payoff_time:  # 还清时间在当前申请时间之前的
            bill_status = 1
            repaid_principal = 0
            repaid_interest = 0
            repaid_cut_interest = 0
            repaid_service_fee = 0
            repaid_management_fee = 0
            repaid_overdue_interest = 0
            repaid_penalty = 0
            discount_amount = 0
            waive_amount = 0
            if current_apply_time[:10] > repayment_date:
                bill_category = 'ovd_onloan'  # 逾期在贷
                ovd_days = get_days_inter(current_apply_time, repayment_date + ' 00:00:00')
            else:
                bill_category = 'onloan'  # 未到还款日的在贷
                ovd_days = 0
    if extension_count == 0 and settlement_type == 2:  # 展期原始单只有展期费用
        bill_category = 'ext'
        ovd_days = 0
    if extension_count > 0:  # 针对展期单 计算逾期天数及类别
        if bill_status == 1:  # 当前展期仍逾期
            if current_apply_time[:10] > repayment_date:
                bill_category = 'ext_ovd_onloan'  # 展期逾期在贷
                ovd_days = get_days_inter(current_apply_time, repayment_date + ' 00:00:00')
            else:
                bill_category = 'ext_onloan'  # 未到还款日的的展期在贷
                ovd_days = 0
        if bill_status == 2:  # 展期逾期
            if current_apply_time >= payoff_time:  # 对于还清的账单判断还清类型
                ovd_days = get_days_inter(payoff_time, repayment_date + ' 00:00:00')
                if ovd_days == 0:
                    bill_category = 'ext_payoff'  # 展期正常结清
                elif ovd_days > 0:
                    bill_category = 'ext_ovd_payoff'  # 展期逾期结清
                elif ovd_days < 0:
                    bill_category = 'ext_pre_payoff'  # 展期提前还清
            elif current_apply_time < payoff_time:  # 还清时间在当前申请时间之前的
                bill_status = 1
                repaid_principal = 0
                repaid_interest = 0
                repaid_cut_interest = 0
                repaid_service_fee = 0
                repaid_management_fee = 0
                repaid_overdue_interest = 0
                repaid_penalty = 0
                discount_amount = 0
                waive_amount = 0
                if current_apply_time[:10] > repayment_date:
                    bill_category = 'ext_ovd_onloan'  # 展期逾期在贷
                    ovd_days = get_days_inter(current_apply_time, repayment_date + ' 00:00:00')
                else:
                    bill_category = 'ext_onloan'  # 未到还款日的在贷
                    ovd_days = 0
    if interest > 0:
        repaid_amt_sum = repaid_principal + repaid_interest + repaid_cut_interest + repaid_service_fee + repaid_management_fee + repaid_overdue_interest + repaid_penalty
    else:
        repaid_amt_sum = repaid_principal + repaid_interest + repaid_service_fee + repaid_management_fee + repaid_overdue_interest + repaid_penalty
    return repaid_principal, repaid_interest, repaid_cut_interest, repaid_service_fee, repaid_management_fee, repaid_overdue_interest, repaid_penalty, discount_amount, waive_amount, ovd_days, bill_category, repaid_amt_sum


def get_first_payoff_features(history_merge_installment,
                              history_order_data,
                              payoff_type='payoff',
                              current_apply_time=None,
                              current_loan_amount=None,
                              register_time=None,
                              feature_type='all'):
    import numpy as np
    from datetime import datetime
    first_payoff_feature_names = []
    first_payoff_feature_values = []
    history_order_data['apply_time'] = history_order_data.apply_time.astype(str)
    history_payoff_installment = history_merge_installment[
        history_merge_installment.bill_category.str.contains(payoff_type)].copy()

    if feature_type == 'all':
        history_payoff_installment = history_payoff_installment.copy()
    elif 'app' in feature_type:
        history_payoff_installment = history_payoff_installment[history_payoff_installment.app_type == feature_type]
    elif 'product' in feature_type:
        history_payoff_installment = history_payoff_installment[history_payoff_installment.product_type == feature_type]

    if len(history_payoff_installment) > 0:
        history_payoff_installment['payoff_sort'] = history_payoff_installment.groupby(['user_id'])['update_time'].rank(
            method='first', ascending=True)  # 还清排序, 正序
        history_payoff_installment['payoff_sort_reverse'] = history_payoff_installment.groupby(['user_id'])[
            'update_time'].rank(method='first', ascending=False)  # 还清排序 倒序
        history_payoff_installment['payoff_day_inter'] = (pd.to_datetime(current_apply_time) - pd.to_datetime(
            history_payoff_installment['update_time'])).dt.days  # 当前申请时间距离每次还清时间间隔
        history_payoff_installment['reg_day_inter'] = (
                pd.to_datetime(history_payoff_installment['update_time']) - pd.to_datetime(
            register_time)).dt.days  # 还清时间距离注册时间的间隔
        first_payoff_time = history_payoff_installment[history_payoff_installment.payoff_sort == 1].update_time.values[
            0]
        first_payoff_type = \
            history_payoff_installment[history_payoff_installment.payoff_sort == 1].bill_category.values[0]  # 第一次结清订单类型
        first_payoff_repaid_amt = \
            history_payoff_installment[history_payoff_installment.payoff_sort == 1].repaid_amt_sum.values[
                0]  # 第一次结清订单金额
        first_payoff_ovd_days = history_payoff_installment[history_payoff_installment.payoff_sort == 1].ovd_days.values[
            0]  # 第一次结清逾期天数 小于0则为替换还清，大于0则为逾期
        first_payoff_amt = \
            history_payoff_installment[history_payoff_installment.payoff_sort == 1].installment_amount.values[0]
        first_payoff_current_days = get_days_inter(current_apply_time, first_payoff_time)  # 第一笔结清订单距离申请订单时间差
        first_payoff_reg_days = get_days_inter(first_payoff_time, register_time)  # 第一笔结清订单距离注册订单时间差
        first_payoff_current_amt_diff = current_loan_amount - first_payoff_amt  # 第一笔结清金额与当前申请金额的差值j
        first_payoff_current_payoff_cnt = len(
            history_payoff_installment[history_payoff_installment.payoff_sort > 1])  # 第一笔结清订单与申请单之间 总的还清次数
        first_payoff_onloan_days = first_payoff_ovd_days + 7  # 第一笔还清在贷天数，小于7为提前还清，大于7为逾期还清d
        first_payoff_contribution_value = first_payoff_onloan_days * first_payoff_amt  # 第一笔结清贡献值
        # 第一次结清单与申请单之间的订单特征
        history_order_data_tmp = history_order_data[history_order_data.apply_time > first_payoff_time]
        fisrt_payoff_after_apply_cnt = len(history_order_data_tmp)  # 第一笔结清订单与申请订单之间的 申请订单数
        fisrt_payoff_after_apply_pass_cnt = len(
            history_order_data_tmp[history_order_data_tmp.status == 21])  # 第一笔结清订单与申请订单之间的放款订单数
        fisrt_payoff_after_apply_rej_cnt = len(
            history_order_data_tmp[history_order_data_tmp.status == 22])  # 第一笔结清订单与申请订单之间的拒绝订单数

        fisrt_payoff_after_apply_amt_max = history_order_data_tmp.loan_amount.max()  # 第一笔结清订单与申请订单之间的申请金额最大值
        fisrt_payoff_after_apply_amt_min = history_order_data_tmp.loan_amount.min()  # 第一笔结清订单与申请订单之间的申请金额最小值
        fisrt_payoff_after_apply_amt_avg = history_order_data_tmp.loan_amount.mean()  # 第一笔结清订单与申请订单之间的申请金额均值
        fisrt_payoff_after_apply_amt_sum = history_order_data_tmp.loan_amount.sum()  # 第一笔结清订单与申请订单之间的申请金额和
        fisrt_payoff_after_apply_amt_std = history_order_data_tmp.loan_amount.std()  # 第一笔结清订单与申请订单之间的申请金额标准差

        fisrt_payoff_after_apply_pass_amt_max = history_order_data_tmp[
            history_order_data_tmp.status == 21].loan_amount.max()  # 第一笔结清订单与通过订单之间的通过金额最大值
        fisrt_payoff_after_apply_pass_amt_min = history_order_data_tmp[
            history_order_data_tmp.status == 21].loan_amount.min()  # 第一笔结清订单与通过订单之间的通过金额最小值
        fisrt_payoff_after_apply_pass_amt_avg = history_order_data_tmp[
            history_order_data_tmp.status == 21].loan_amount.mean()  # 第一笔结清订单与通过订单之间的通过金额均值
        fisrt_payoff_after_apply_pass_amt_sum = history_order_data_tmp[
            history_order_data_tmp.status == 21].loan_amount.sum()  # 第一笔结清订单与通过订单之间的通过金额和
        fisrt_payoff_after_apply_pass_amt_std = history_order_data_tmp[
            history_order_data_tmp.status == 21].loan_amount.std()  # 第一笔结清订单与通过订单之间的通过金额标准差

        fisrt_payoff_after_apply_rej_amt_max = history_order_data_tmp[
            history_order_data_tmp.status == 22].loan_amount.max()  # 第一笔结清订单与拒绝订单之间的拒绝金额最大值
        fisrt_payoff_after_apply_rej_amt_min = history_order_data_tmp[
            history_order_data_tmp.status == 22].loan_amount.min()  # 第一笔结清订单与拒绝订单之间的拒绝金额最小值
        fisrt_payoff_after_apply_rej_amt_avg = history_order_data_tmp[
            history_order_data_tmp.status == 22].loan_amount.mean()  # 第一笔结清订单与拒绝订单之间的拒绝金额均值
        fisrt_payoff_after_apply_rej_amt_sum = history_order_data_tmp[
            history_order_data_tmp.status == 22].loan_amount.sum()  # 第一笔结清订单与拒绝订单之间的拒绝金额和
        fisrt_payoff_after_apply_rej_amt_std = history_order_data_tmp[
            history_order_data_tmp.status == 22].loan_amount.std()  # 第一笔结清订单与拒绝订单之间的拒绝金额标准差

        # 计算结清之后申请订单的间隔
        after_order = history_order_data_tmp.apply_time.to_list()
        if len(after_order) > 0:
            after_order.append(current_apply_time)
            date_objects = [datetime.strptime(date, "%Y-%m-%d %H:%M:%S") for date in after_order]
            intervals = [(date_objects[i + 1] - date_objects[i]).days for i in range(len(date_objects) - 1)]
            after_payoff_inter_max = max(intervals)  # 第一笔结清订单与申请订单之间的 所有申请订单间隔最大值
            after_payoff_inter_min = min(intervals)  # 第一笔结清订单与申请订单之间的 所有申请订单间隔最小值
            after_payoff_inter_avg = np.mean(intervals)  # 第一笔结清订单与申请订单之间的 所有申请订单间隔平均值
            after_payoff_inter_std = np.std(intervals)  # 第一笔结清订单与申请订单之间的 所有申请订单间隔标准差
        else:
            after_payoff_inter_max = -999
            after_payoff_inter_min = -999
            after_payoff_inter_avg = -999
            after_payoff_inter_std = -999

        # 第一笔结清之前的数据
        history_order_before_tmp = history_order_data[history_order_data.apply_time < first_payoff_time]
        before_payoff_order_cnt = len(history_order_data_tmp)  # 第一笔结清单之前申请的订单数
        before_payoff_order_amt = history_order_before_tmp.loan_amount.sum()  # 第一笔结清单之前申请的订单金额和
        before_payoff_order_pass_cnt = len(
            history_order_data_tmp[history_order_data_tmp.status == 21])  # 第一笔结清单之前放款的订单数
        before_payoff_order_pass_amt = history_order_data_tmp[
            history_order_data_tmp.status == 21].loan_amount.sum()  # 第一笔结清单之前申请的放款金额和
        before_payoff_order_rej_cnt = len(history_order_data_tmp[history_order_data_tmp.status == 22])  # 第一笔结清单之前拒绝的订单数
        before_payoff_order_rej_amt = history_order_data_tmp[
            history_order_data_tmp.status == 22].loan_amount.sum()  # 第一笔结清单之前申请的拒绝金额和
    else:
        first_payoff_type = -999
        first_payoff_repaid_amt = -999
        first_payoff_ovd_days = -999
        first_payoff_amt = -999
        first_payoff_current_days = -999
        first_payoff_reg_days = -999
        first_payoff_current_amt_diff = -999
        first_payoff_current_payoff_cnt = -999
        first_payoff_onloan_days = -999
        first_payoff_contribution_value = -999
        fisrt_payoff_after_apply_cnt = -999
        fisrt_payoff_after_apply_pass_cnt = -999
        fisrt_payoff_after_apply_rej_cnt = -999
        fisrt_payoff_after_apply_amt_max = -999
        fisrt_payoff_after_apply_amt_min = -999
        fisrt_payoff_after_apply_amt_avg = -999
        fisrt_payoff_after_apply_amt_sum = -999
        fisrt_payoff_after_apply_amt_std = -999
        fisrt_payoff_after_apply_pass_amt_max = -999
        fisrt_payoff_after_apply_pass_amt_min = -999
        fisrt_payoff_after_apply_pass_amt_avg = -999
        fisrt_payoff_after_apply_pass_amt_sum = -999
        fisrt_payoff_after_apply_pass_amt_std = -999
        fisrt_payoff_after_apply_rej_amt_max = -999
        fisrt_payoff_after_apply_rej_amt_min = -999
        fisrt_payoff_after_apply_rej_amt_avg = -999
        fisrt_payoff_after_apply_rej_amt_sum = -999
        fisrt_payoff_after_apply_rej_amt_std = -999
        after_payoff_inter_max = -999
        after_payoff_inter_min = -999
        after_payoff_inter_avg = -999
        after_payoff_inter_std = -999
        before_payoff_order_cnt = -999
        before_payoff_order_amt = -999
        before_payoff_order_pass_cnt = -999
        before_payoff_order_pass_amt = -999
        before_payoff_order_rej_cnt = -999
        before_payoff_order_rej_amt = -999

    first_payoff_feature_values.extend([
                                        first_payoff_repaid_amt,
                                        first_payoff_ovd_days,
                                        first_payoff_amt,
                                        first_payoff_current_days,
                                        first_payoff_reg_days,
                                        first_payoff_current_amt_diff,
                                        first_payoff_current_payoff_cnt,
                                        first_payoff_onloan_days,
                                        first_payoff_contribution_value,
                                        fisrt_payoff_after_apply_cnt,
                                        fisrt_payoff_after_apply_pass_cnt,
                                        fisrt_payoff_after_apply_rej_cnt,
                                        fisrt_payoff_after_apply_amt_max,
                                        fisrt_payoff_after_apply_amt_min,
                                        fisrt_payoff_after_apply_amt_avg,
                                        fisrt_payoff_after_apply_amt_sum,
                                        fisrt_payoff_after_apply_amt_std,
                                        fisrt_payoff_after_apply_pass_amt_max,
                                        fisrt_payoff_after_apply_pass_amt_min,
                                        fisrt_payoff_after_apply_pass_amt_avg,
                                        fisrt_payoff_after_apply_pass_amt_sum,
                                        fisrt_payoff_after_apply_pass_amt_std,
                                        fisrt_payoff_after_apply_rej_amt_max,
                                        fisrt_payoff_after_apply_rej_amt_min,
                                        fisrt_payoff_after_apply_rej_amt_avg,
                                        fisrt_payoff_after_apply_rej_amt_sum,
                                        fisrt_payoff_after_apply_rej_amt_std,
                                        after_payoff_inter_max,
                                        after_payoff_inter_min,
                                        after_payoff_inter_avg,
                                        after_payoff_inter_std,
                                        before_payoff_order_cnt,
                                        before_payoff_order_amt,
                                        before_payoff_order_pass_cnt,
                                        before_payoff_order_pass_amt,
                                        before_payoff_order_rej_cnt,
                                        before_payoff_order_rej_amt, ])
    first_payoff_feature_names.extend([
                                       f'{feature_type}_{payoff_type}_first_payoff_repaid_amt',
                                       f'{feature_type}_{payoff_type}_first_payoff_ovd_days',
                                       f'{feature_type}_{payoff_type}_first_payoff_amt',
                                       f'{feature_type}_{payoff_type}_first_payoff_current_days',
                                       f'{feature_type}_{payoff_type}_first_payoff_reg_days',
                                       f'{feature_type}_{payoff_type}_first_payoff_current_amt_diff',
                                       f'{feature_type}_{payoff_type}_first_payoff_current_payoff_cnt',
                                       f'{feature_type}_{payoff_type}_first_payoff_onloan_days',
                                       f'{feature_type}_{payoff_type}_first_payoff_contribution_value',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_cnt',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_pass_cnt',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_rej_cnt',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_amt_max',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_amt_min',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_amt_avg',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_amt_sum',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_amt_std',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_pass_amt_max',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_pass_amt_min',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_pass_amt_avg',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_pass_amt_sum',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_pass_amt_std',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_rej_amt_max',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_rej_amt_min',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_rej_amt_avg',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_rej_amt_sum',
                                       f'{feature_type}_{payoff_type}_fisrt_payoff_after_apply_rej_amt_std',
                                       f'{feature_type}_{payoff_type}_fisrt_after_payoff_inter_max',
                                       f'{feature_type}_{payoff_type}_fisrt_after_payoff_inter_min',
                                       f'{feature_type}_{payoff_type}_fisrt_after_payoff_inter_avg',
                                       f'{feature_type}_{payoff_type}_fisrt_after_payoff_inter_std',
                                       f'{feature_type}_{payoff_type}_fisrt_before_payoff_order_cnt',
                                       f'{feature_type}_{payoff_type}_fisrt_before_payoff_order_amt',
                                       f'{feature_type}_{payoff_type}_fisrt_before_payoff_order_pass_cnt',
                                       f'{feature_type}_{payoff_type}_fisrt_before_payoff_order_pass_amt',
                                       f'{feature_type}_{payoff_type}_fisrt_before_payoff_order_rej_cnt',
                                       f'{feature_type}_{payoff_type}_fisrt_before_payoff_order_rej_amt', ])
    return dict(zip(first_payoff_feature_names, first_payoff_feature_values))


def get_last_payoff_features(history_merge_installment,
                             history_order_data,
                             payoff_type='payoff',
                             current_apply_time=None,
                             current_loan_amount=None,
                             register_time=None,
                             feature_type='all'):
    import numpy as np
    from datetime import datetime
    last_payoff_feature_names = []
    last_payoff_feature_values = []
    history_order_data['apply_time'] = history_order_data.apply_time.astype(str)
    history_payoff_installment = history_merge_installment[
        history_merge_installment.bill_category.str.contains(payoff_type)].copy()  # 筛选符合还清条件的数据
    if feature_type == 'all':
        history_payoff_installment = history_payoff_installment.copy()
    elif 'app' in feature_type:
        history_payoff_installment = history_payoff_installment[history_payoff_installment.app_type == feature_type]
    elif 'product' in feature_type:
        history_payoff_installment = history_payoff_installment[history_payoff_installment.product_type == feature_type]

    if len(history_payoff_installment) > 0:
        history_payoff_installment['payoff_sort'] = history_payoff_installment.groupby(['user_id'])['update_time'].rank(
            method='first', ascending=True)  # 还清排序, 正序
        history_payoff_installment['payoff_sort_reverse'] = history_payoff_installment.groupby(['user_id'])[
            'update_time'].rank(method='first', ascending=False)  # 还清排序 倒序
        history_payoff_installment['payoff_day_inter'] = (pd.to_datetime(current_apply_time) - pd.to_datetime(
            history_payoff_installment['update_time'])).dt.days  # 当前申请时间距离每次还清时间间隔
        history_payoff_installment['reg_day_inter'] = (
                pd.to_datetime(history_payoff_installment['update_time']) - pd.to_datetime(
            register_time)).dt.days  # 上一笔还清时间距离注册时间的间隔
        last_payoff_time = \
            history_payoff_installment[history_payoff_installment.payoff_sort_reverse == 1].update_time.values[
                0]  # 上一笔还清时间

        last_payoff_type = \
            history_payoff_installment[history_payoff_installment.payoff_sort_reverse == 1].bill_category.values[
                0]  # 上一笔结清订单类型
        last_payoff_repaid_amt = \
            history_payoff_installment[history_payoff_installment.payoff_sort_reverse == 1].repaid_amt_sum.values[
                0]  # 上一笔结清订单金额
        last_payoff_ovd_days = \
            history_payoff_installment[history_payoff_installment.payoff_sort_reverse == 1].ovd_days.values[
                0]  # 上一笔结清逾期天数 小于0则为替换还清，大于0则为逾期
        last_payoff_amt = \
            history_payoff_installment[history_payoff_installment.payoff_sort_reverse == 1].installment_amount.values[
                0]  # 上一笔贷款金额
        last_payoff_current_days = get_days_inter(current_apply_time, last_payoff_time)  # 上一笔结清订单距离申请订单时间差
        last_payoff_reg_days = get_days_inter(last_payoff_time, register_time)  # 上一笔结清订单距离注册订单时间差
        last_payoff_current_amt_diff = current_loan_amount - last_payoff_amt  # 上一笔结清金额与当前申请金额的差值
        last_payoff_onloan_days = last_payoff_ovd_days + 7  # 上一笔还清在贷天数，小于7为提前还清，大于7为逾期还清d
        last_payoff_contribution_value = last_payoff_onloan_days * last_payoff_amt  # 上一笔结清贡献值

        # 上一笔结清单与申请单之间的订单特征
        history_order_data_tmp = history_order_data[history_order_data.apply_time > last_payoff_time].copy()

        last_payoff_after_apply_cnt = len(history_order_data_tmp)  # 上一笔结清订单与申请订单之间的 申请订单数
        last_payoff_after_apply_pass_cnt = len(
            history_order_data_tmp[history_order_data_tmp.status == 21])  # 上一笔结清订单与申请订单之间的放款订单数
        last_payoff_after_apply_rej_cnt = len(
            history_order_data_tmp[history_order_data_tmp.status == 22])  # 上一笔结清订单与申请订单之间的拒绝订单数

        last_payoff_after_apply_amt_max = history_order_data_tmp.loan_amount.max()  # 上一笔结清订单与申请订单之间的申请金额最大值
        last_payoff_after_apply_amt_min = history_order_data_tmp.loan_amount.min()  # 上一笔结清订单与申请订单之间的申请金额最小值
        last_payoff_after_apply_amt_avg = history_order_data_tmp.loan_amount.mean()  # 上一笔结清订单与申请订单之间的申请金额均值
        last_payoff_after_apply_amt_sum = history_order_data_tmp.loan_amount.sum()  # 上一笔结清订单与申请订单之间的申请金额和
        last_payoff_after_apply_amt_std = history_order_data_tmp.loan_amount.std()  # 上一笔结清订单与申请订单之间的申请金额标准差

        last_payoff_after_apply_pass_amt_max = history_order_data_tmp[
            history_order_data_tmp.status == 21].loan_amount.max()  # 上一笔结清订单与通过订单之间的通过金额最大值
        last_payoff_after_apply_pass_amt_min = history_order_data_tmp[
            history_order_data_tmp.status == 21].loan_amount.min()  # 上一笔结清订单与通过订单之间的通过金额最小值
        last_payoff_after_apply_pass_amt_avg = history_order_data_tmp[
            history_order_data_tmp.status == 21].loan_amount.mean()  # 上一笔结清订单与通过订单之间的通过金额均值
        last_payoff_after_apply_pass_amt_sum = history_order_data_tmp[
            history_order_data_tmp.status == 21].loan_amount.sum()  # 上一笔结清订单与通过订单之间的通过金额和
        last_payoff_after_apply_pass_amt_std = history_order_data_tmp[
            history_order_data_tmp.status == 21].loan_amount.std()  # 上一笔结清订单与通过订单之间的通过金额标准差

        last_payoff_after_apply_rej_amt_max = history_order_data_tmp[
            history_order_data_tmp.status == 22].loan_amount.max()  # 上一笔结清订单与拒绝订单之间的拒绝金额最大值
        last_payoff_after_apply_rej_amt_min = history_order_data_tmp[
            history_order_data_tmp.status == 22].loan_amount.min()  # 上一笔结清订单与拒绝订单之间的拒绝金额最小值
        last_payoff_after_apply_rej_amt_avg = history_order_data_tmp[
            history_order_data_tmp.status == 22].loan_amount.mean()  # 上一笔结清订单与拒绝订单之间的拒绝金额均值
        last_payoff_after_apply_rej_amt_sum = history_order_data_tmp[
            history_order_data_tmp.status == 22].loan_amount.sum()  # 上一笔结清订单与拒绝订单之间的拒绝金额和
        last_payoff_after_apply_rej_amt_std = history_order_data_tmp[
            history_order_data_tmp.status == 22].loan_amount.std()  # 上一笔结清订单与拒绝订单之间的拒绝金额标准差

        # 计算结清之后申请订单的间隔
        if len(history_order_data_tmp) > 0:
            last_payoff_after_max_apply_time = history_order_data_tmp.apply_time.max()
            last_payoff_after_max_apply_time_inter = get_days_inter(current_apply_time,
                                                                    last_payoff_after_max_apply_time)  # 上一笔结清订单 和本次申请 时间内 最近一笔申请订单 距离申请订单的时间差
            last_payoff_after_max_apply_time_inter_rate = fea_div_v2(last_payoff_after_max_apply_time_inter,
                                                                     last_payoff_current_days)  # 上一笔结清订单 和本次申请 时间内 最近一笔申请订单 距离申请订单的时间差/ 上一笔结清订单结清时间 距离 本次申请时间差

            last_payoff_after_max_apply_pass_time = history_order_data_tmp[
                history_order_data_tmp.status == 21].apply_time.max()
            if str(last_payoff_after_max_apply_pass_time) != 'nan':
                last_payoff_after_max_apply_pass_time_inter = get_days_inter(current_apply_time,
                                                                             last_payoff_after_max_apply_pass_time)  # 上一笔结清订单 和本次申请 时间内 最近一笔放款订单 距离申请订单的时间差
                last_payoff_after_max_apply_pass_time_inter_rate = fea_div_v2(
                    last_payoff_after_max_apply_pass_time_inter,
                    last_payoff_current_days)  # 上一笔结清订单 和本次申请 时间内 最近一笔放款订单 距离申请订单的时间差/ 上一笔结清订单结清时间 距离 本次申请时间差
            else:
                last_payoff_after_max_apply_pass_time_inter = -999
                last_payoff_after_max_apply_pass_time_inter_rate = -999

            last_payoff_after_max_apply_rej_time = history_order_data_tmp[
                history_order_data_tmp.status == 22].apply_time.max()
            if str(last_payoff_after_max_apply_rej_time) != 'nan':
                last_payoff_after_max_apply_rej_time_inter = get_days_inter(current_apply_time,
                                                                            last_payoff_after_max_apply_rej_time)  # 上一笔结清订单 和本次申请 时间内 最近一笔拒绝订单 距离申请订单的时间差
                last_payoff_after_max_apply_rej_time_inter_rate = fea_div_v2(last_payoff_after_max_apply_rej_time_inter,
                                                                             last_payoff_current_days)  # 上一笔结清订单 和本次申请 时间内 最近一笔拒绝订单 距离申请订单的时间差 /上一笔结清订单结清时间 距离 本次申请时间差
            else:
                last_payoff_after_max_apply_rej_time_inter = -999
                last_payoff_after_max_apply_pass_time_inter_rate = -999

            after_order = history_order_data_tmp.apply_time.to_list()
            after_order.append(current_apply_time)
            date_objects = [datetime.strptime(date, "%Y-%m-%d %H:%M:%S") for date in after_order]
            intervals = [(date_objects[i + 1] - date_objects[i]).days for i in range(len(date_objects) - 1)]
            after_payoff_inter_max = max(intervals)  # 上一笔结清订单与申请订单之间的 所有申请订单间隔最大值
            after_payoff_inter_min = min(intervals)  # 上一笔结清订单与申请订单之间的 所有申请订单间隔最小值
            after_payoff_inter_avg = np.mean(intervals)  # 上一笔结清订单与申请订单之间的 所有申请订单间隔平均值
            after_payoff_inter_std = np.std(intervals)  # 上一笔结清订单与申请订单之间的 所有申请订单间隔标准差

        else:
            last_payoff_after_max_apply_time_inter = -999
            last_payoff_after_max_apply_pass_time_inter = -999
            last_payoff_after_max_apply_rej_time_inter = -999
            last_payoff_after_max_apply_time_inter_rate = -999
            last_payoff_after_max_apply_pass_time_inter_rate = -999
            last_payoff_after_max_apply_rej_time_inter_rate = -999
            after_payoff_inter_max = -999
            after_payoff_inter_min = -999
            after_payoff_inter_avg = -999
            after_payoff_inter_std = -999

        # 上一笔结清之前的数据
        history_order_before_tmp = history_order_data[history_order_data.apply_time < last_payoff_time].copy()
        before_payoff_order_cnt = len(history_order_data_tmp)  # 上一笔结清单之前申请的订单数
        before_payoff_order_amt = history_order_before_tmp.loan_amount.sum()  # 上一笔结清单之前申请的订单金额和
        before_payoff_order_pass_cnt = len(
            history_order_data_tmp[history_order_data_tmp.status == 21])  # 上一笔结清单之前放款的订单数
        before_payoff_order_pass_amt = history_order_data_tmp[
            history_order_data_tmp.status == 21].loan_amount.sum()  # 上一笔结清单之前申请的放款金额和
        before_payoff_order_rej_cnt = len(history_order_data_tmp[history_order_data_tmp.status == 22])  # 上一笔结清单之前拒绝的订单数
        before_payoff_order_rej_amt = history_order_data_tmp[
            history_order_data_tmp.status == 22].loan_amount.sum()  # 上一笔结清单之前申请的拒绝金额和
    else:
        last_payoff_type = -999
        last_payoff_repaid_amt = -999
        last_payoff_ovd_days = -999
        last_payoff_amt = -999
        last_payoff_current_days = -999
        last_payoff_reg_days = -999
        last_payoff_current_amt_diff = -999
        last_payoff_onloan_days = -999
        last_payoff_contribution_value = -999
        last_payoff_after_apply_cnt = -999
        last_payoff_after_apply_pass_cnt = -999
        last_payoff_after_apply_rej_cnt = -999
        last_payoff_after_apply_amt_max = -999
        last_payoff_after_apply_amt_min = -999
        last_payoff_after_apply_amt_avg = -999
        last_payoff_after_apply_amt_sum = -999
        last_payoff_after_apply_amt_std = -999
        last_payoff_after_apply_pass_amt_max = -999
        last_payoff_after_apply_pass_amt_min = -999
        last_payoff_after_apply_pass_amt_avg = -999
        last_payoff_after_apply_pass_amt_sum = -999
        last_payoff_after_apply_pass_amt_std = -999
        last_payoff_after_apply_rej_amt_max = -999
        last_payoff_after_apply_rej_amt_min = -999
        last_payoff_after_apply_rej_amt_avg = -999
        last_payoff_after_apply_rej_amt_sum = -999
        last_payoff_after_apply_rej_amt_std = -999
        last_payoff_after_max_apply_time = -999
        last_payoff_after_max_apply_time_inter = -999
        last_payoff_after_max_apply_time_inter_rate = -999
        last_payoff_after_max_apply_pass_time_inter = -999
        last_payoff_after_max_apply_pass_time_inter_rate = -999
        last_payoff_after_max_apply_rej_time_inter = -999
        last_payoff_after_max_apply_rej_time_inter_rate = -999
        after_payoff_inter_max = -999
        after_payoff_inter_min = -999
        after_payoff_inter_avg = -999
        after_payoff_inter_std = -999
        before_payoff_order_cnt = -999
        before_payoff_order_amt = -999
        before_payoff_order_pass_cnt = -999
        before_payoff_order_pass_amt = -999
        before_payoff_order_rej_cnt = -999
        before_payoff_order_rej_amt = -999

    last_payoff_feature_values.extend([
                                       last_payoff_amt,
                                       last_payoff_ovd_days,
                                       last_payoff_amt,
                                       last_payoff_current_days,
                                       last_payoff_reg_days,
                                       last_payoff_current_amt_diff,
                                       last_payoff_onloan_days,
                                       last_payoff_contribution_value,
                                       last_payoff_after_apply_cnt,
                                       last_payoff_after_apply_pass_cnt,
                                       last_payoff_after_apply_rej_cnt,
                                       last_payoff_after_apply_amt_max,
                                       last_payoff_after_apply_amt_min,
                                       last_payoff_after_apply_amt_avg,
                                       last_payoff_after_apply_amt_sum,
                                       last_payoff_after_apply_amt_std,
                                       last_payoff_after_apply_pass_amt_max,
                                       last_payoff_after_apply_pass_amt_min,
                                       last_payoff_after_apply_pass_amt_avg,
                                       last_payoff_after_apply_pass_amt_sum,
                                       last_payoff_after_apply_pass_amt_std,
                                       last_payoff_after_apply_rej_amt_max,
                                       last_payoff_after_apply_rej_amt_min,
                                       last_payoff_after_apply_rej_amt_avg,
                                       last_payoff_after_apply_rej_amt_sum,
                                       last_payoff_after_apply_rej_amt_std,
                                       after_payoff_inter_max,
                                       after_payoff_inter_min,
                                       after_payoff_inter_avg,
                                       after_payoff_inter_std,
                                       before_payoff_order_cnt,
                                       before_payoff_order_amt,
                                       before_payoff_order_pass_cnt,
                                       before_payoff_order_pass_amt,
                                       before_payoff_order_rej_cnt,
                                       before_payoff_order_rej_amt, ])
    last_payoff_feature_names.extend([
                                      f'{feature_type}_{payoff_type}_last_payoff_amt',
                                      f'{feature_type}_{payoff_type}_last_payoff_ovd_days',
                                      f'{feature_type}_{payoff_type}_last_payoff_amt',
                                      f'{feature_type}_{payoff_type}_last_payoff_current_days',
                                      f'{feature_type}_{payoff_type}_last_payoff_reg_days',
                                      f'{feature_type}_{payoff_type}_last_payoff_current_amt_diff',
                                      f'{feature_type}_{payoff_type}_last_payoff_onloan_days',
                                      f'{feature_type}_{payoff_type}_last_payoff_contribution_value',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_cnt',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_pass_cnt',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_rej_cnt',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_amt_max',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_amt_min',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_amt_avg',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_amt_sum',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_amt_std',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_pass_amt_max',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_pass_amt_min',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_pass_amt_avg',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_pass_amt_sum',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_pass_amt_std',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_rej_amt_max',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_rej_amt_min',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_rej_amt_avg',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_rej_amt_sum',
                                      f'{feature_type}_{payoff_type}_last_payoff_after_apply_rej_amt_std',
                                      f'{feature_type}_{payoff_type}_last_after_payoff_inter_max',
                                      f'{feature_type}_{payoff_type}_last_after_payoff_inter_min',
                                      f'{feature_type}_{payoff_type}_last_after_payoff_inter_avg',
                                      f'{feature_type}_{payoff_type}_last_after_payoff_inter_std',
                                      f'{feature_type}_{payoff_type}_last_before_payoff_order_cnt',
                                      f'{feature_type}_{payoff_type}_last_before_payoff_order_amt',
                                      f'{feature_type}_{payoff_type}_last_before_payoff_order_pass_cnt',
                                      f'{feature_type}_{payoff_type}_last_before_payoff_order_pass_amt',
                                      f'{feature_type}_{payoff_type}_last_before_payoff_order_rej_cnt',
                                      f'{feature_type}_{payoff_type}_last_before_payoff_order_rej_amt', ])
    return dict(zip(last_payoff_feature_names, last_payoff_feature_values))


def get_day_payoff_features(history_merge_installment,
                            payoff_type='payoff',
                            day_list=[1, 3, 7, 15, 30, 60, 90, 180, 'all'],
                            records_list=[1, 3, 7, 15, 30],
                            current_apply_time=None,
                            feature_type='all'):
    import numpy as np
    from datetime import datetime
    day_payoff_feature_names = []
    day_payoff_feature_values = []
    history_payoff_installment = history_merge_installment[
        history_merge_installment.bill_category.str.contains(payoff_type)].copy()  # 筛选符合还清条件的数据
    if feature_type == 'all':
        history_payoff_installment = history_payoff_installment.copy()
    elif 'app' in feature_type:
        history_payoff_installment = history_payoff_installment[history_payoff_installment.app_type == feature_type]
    elif 'product' in feature_type:
        history_payoff_installment = history_payoff_installment[history_payoff_installment.product_type == feature_type]

    history_payoff_installment['payoff_inter'] = (
            pd.to_datetime(current_apply_time) - pd.to_datetime(history_payoff_installment.update_time)).dt.days
    history_payoff_installment['payoff_sort'] = history_payoff_installment.groupby(['user_id'])['update_time'].rank(
        method='first', ascending=True)  # 还清排序, 正序
    history_payoff_installment['payoff_sort_reverse'] = history_payoff_installment.groupby(['user_id'])[
        'update_time'].rank(method='first', ascending=False)  # 还清排序 倒序

    for day in day_list:
        if day == 'all':
            history_payoff_installment_tmp = history_payoff_installment.copy()  # 最近N天的申请数据
        else:
            history_payoff_installment_tmp = history_payoff_installment[
                history_payoff_installment.payoff_inter <= day].copy()
        payoff_order_cnt_day = len(history_payoff_installment_tmp)  # 最近N天结清的订单数
        payoff_order_amt_max_day = history_payoff_installment_tmp.installment_amount.max()  # 最近N天结清的订单金额最大值
        payoff_order_amt_min_day = history_payoff_installment_tmp.installment_amount.min()  # 最近N天结清的订单金额最小值
        payoff_order_amt_avg_day = history_payoff_installment_tmp.installment_amount.mean()  # 最近N天结清的订单金额平均值
        payoff_order_amt_std_day = history_payoff_installment_tmp.installment_amount.std()  # 最近N天结清的订单金额标准差
        payoff_order_amt_sum_day = history_payoff_installment_tmp.installment_amount.sum()  # 最近N天结清的订单金额和

        payoff_order_amt_sum_day_rate = fea_div_v2(payoff_order_amt_sum_day,
                                                   history_merge_installment.installment_amount.sum())  # 最近N天结清的订单金额sum/总账单sum
        payoff_order_cnt_day_rate = fea_div_v2(payoff_order_cnt_day, len(history_merge_installment))  # 最近N天结清订单数/总账单数

        if payoff_order_cnt_day > 1:
            payoff_order = history_payoff_installment_tmp.update_time.to_list()
            date_objects = [datetime.strptime(date, "%Y-%m-%d %H:%M:%S") for date in payoff_order]
            intervals = [(date_objects[i + 1] - date_objects[i]).days for i in range(len(date_objects) - 1)]
            after_payoff_inter_max_day = max(intervals)  # 最近N天结清时间的间隔最大值
            after_payoff_inter_min_day = min(intervals)  # 最近N天结清时间的间隔最大值
            after_payoff_inter_avg_day = np.mean(intervals)  # 最近N天结清时间的间隔最大值
            after_payoff_inter_std_day = np.std(intervals)  # 最近N天结清时间的间隔最大值
        else:
            after_payoff_inter_max_day = -999
            after_payoff_inter_min_day = -999
            after_payoff_inter_avg_day = -999
            after_payoff_inter_std_day = -999

        day_payoff_feature_values.extend([payoff_order_cnt_day,
                                          payoff_order_amt_max_day,
                                          payoff_order_amt_min_day,
                                          payoff_order_amt_avg_day,
                                          payoff_order_amt_std_day,
                                          payoff_order_amt_sum_day,
                                          after_payoff_inter_max_day,
                                          after_payoff_inter_min_day,
                                          after_payoff_inter_avg_day,
                                          after_payoff_inter_std_day,
                                          payoff_order_amt_sum_day_rate,
                                          payoff_order_cnt_day_rate,
                                          ])
        day_payoff_feature_names.extend([f'{feature_type}_{payoff_type}_payoff_order_cnt_{day}d',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_max_{day}d',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_min_{day}d',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_avg_{day}d',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_std_{day}d',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_sum_{day}d',
                                         f'{feature_type}_{payoff_type}_after_payoff_inter_max_{day}d',
                                         f'{feature_type}_{payoff_type}_after_payoff_inter_min_{day}d',
                                         f'{feature_type}_{payoff_type}_after_payoff_inter_avg_{day}d',
                                         f'{feature_type}_{payoff_type}_after_payoff_inter_std_{day}d',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_sum_day_rate_{day}d',
                                         f'{feature_type}_{payoff_type}_payoff_order_cnt_day_rate_{day}d',
                                         ])

    for rd in records_list:
        history_payoff_installment_tmp = history_payoff_installment[
            history_payoff_installment.payoff_sort_reverse <= rd].copy()
        payoff_order_cnt_rd = len(history_payoff_installment_tmp)  # 最近N笔结清的订单数
        payoff_order_amt_max_rd = history_payoff_installment_tmp.installment_amount.max()  # 最近N笔结清的订单金额最大值
        payoff_order_amt_min_rd = history_payoff_installment_tmp.installment_amount.min()  # 最近N笔结清的订单金额最小值
        payoff_order_amt_avg_rd = history_payoff_installment_tmp.installment_amount.mean()  # 最近N笔结清的订单金额平均值
        payoff_order_amt_std_rd = history_payoff_installment_tmp.installment_amount.std()  # 最近N笔结清的订单金额标准差
        payoff_order_amt_sum_rd = history_payoff_installment_tmp.installment_amount.sum()  # 最近N笔结清的订单金额和

        if len(history_payoff_installment_tmp) > 1:
            payoff_order = history_payoff_installment_tmp.update_time.to_list()
            date_objects = [datetime.strptime(date, "%Y-%m-%d %H:%M:%S") for date in payoff_order]
            intervals = [(date_objects[i + 1] - date_objects[i]).days for i in range(len(date_objects) - 1)]
            after_payoff_inter_max_rd = max(intervals)  # 最近N天结清时间的间隔最大值
            after_payoff_inter_min_rd = min(intervals)  # 最近N天结清时间的间隔最大值
            after_payoff_inter_avg_rd = np.mean(intervals)  # 最近N天结清时间的间隔最大值
            after_payoff_inter_std_rd = np.std(intervals)  # 最近N天结清时间的间隔最大值
        else:
            after_payoff_inter_max_rd = -999
            after_payoff_inter_min_rd = -999
            after_payoff_inter_avg_rd = -999
            after_payoff_inter_std_rd = -999

        history_payoff_installment_tmp = history_payoff_installment[history_payoff_installment.payoff_sort <= rd].copy()
        payoff_order_cnt_before_rd = len(history_payoff_installment_tmp)  # 前N笔结清的订单数
        payoff_order_amt_max_before_rd = history_payoff_installment_tmp.installment_amount.max()  # 前N笔结清的订单金额最大值
        payoff_order_amt_min_before_rd = history_payoff_installment_tmp.installment_amount.min()  # 前N笔结清的订单金额最小值
        payoff_order_amt_avg_before_rd = history_payoff_installment_tmp.installment_amount.mean()  # 前N笔结清的订单金额平均值
        payoff_order_amt_std_before_rd = history_payoff_installment_tmp.installment_amount.std()  # 前N笔结清的订单金额标准差
        payoff_order_amt_sum_before_rd = history_payoff_installment_tmp.installment_amount.sum()  # 前N笔结清的订单金额和

        if len(history_payoff_installment_tmp) > 1:
            payoff_order = history_payoff_installment_tmp.update_time.to_list()
            date_objects = [datetime.strptime(date, "%Y-%m-%d %H:%M:%S") for date in payoff_order]
            intervals = [(date_objects[i + 1] - date_objects[i]).days for i in range(len(date_objects) - 1)]
            after_payoff_inter_max_before_rd = max(intervals)  # 前N天结清时间的间隔最大值
            after_payoff_inter_min_before_rd = min(intervals)  # 前N天结清时间的间隔最大值
            after_payoff_inter_avg_before_rd = np.mean(intervals)  # 前N天结清时间的间隔最大值
            after_payoff_inter_std_before_rd = np.std(intervals)  # 前N天结清时间的间隔最大值
        else:
            after_payoff_inter_max_before_rd = -999
            after_payoff_inter_min_before_rd = -999
            after_payoff_inter_avg_before_rd = -999
            after_payoff_inter_std_before_rd = -999

        day_payoff_feature_values.extend([payoff_order_cnt_rd,
                                          payoff_order_amt_max_rd,
                                          payoff_order_amt_min_rd,
                                          payoff_order_amt_avg_rd,
                                          payoff_order_amt_std_rd,
                                          payoff_order_amt_sum_rd,
                                          after_payoff_inter_max_rd,
                                          after_payoff_inter_min_rd,
                                          after_payoff_inter_avg_rd,
                                          after_payoff_inter_std_rd,
                                          payoff_order_cnt_before_rd,
                                          payoff_order_amt_max_before_rd,
                                          payoff_order_amt_min_before_rd,
                                          payoff_order_amt_avg_before_rd,
                                          payoff_order_amt_std_before_rd,
                                          payoff_order_amt_sum_before_rd,
                                          after_payoff_inter_max_before_rd,
                                          after_payoff_inter_min_before_rd,
                                          after_payoff_inter_avg_before_rd,
                                          after_payoff_inter_std_before_rd, ])
        day_payoff_feature_names.extend([f'{feature_type}_{payoff_type}_payoff_order_cnt_{rd}rd',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_max_{rd}rd',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_min_{rd}rd',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_avg_{rd}rd',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_std_{rd}rd',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_sum_{rd}rd',
                                         f'{feature_type}_{payoff_type}_after_payoff_inter_max_{rd}rd',
                                         f'{feature_type}_{payoff_type}_after_payoff_inter_min_{rd}rd',
                                         f'{feature_type}_{payoff_type}_after_payoff_inter_avg_{rd}rd',
                                         f'{feature_type}_{payoff_type}_after_payoff_inter_std_{rd}rd',
                                         f'{feature_type}_{payoff_type}_payoff_order_cnt_before_{rd}rd',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_max_before_{rd}rd',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_min_before_{rd}rd',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_avg_before_{rd}rd',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_std_before_{rd}rd',
                                         f'{feature_type}_{payoff_type}_payoff_order_amt_sum_before_{rd}rd',
                                         f'{feature_type}_{payoff_type}_after_payoff_inter_max_before_{rd}rd',
                                         f'{feature_type}_{payoff_type}_after_payoff_inter_min_before_{rd}rd',
                                         f'{feature_type}_{payoff_type}_after_payoff_inter_avg_before_{rd}rd',
                                         f'{feature_type}_{payoff_type}_after_payoff_inter_std_before_{rd}rd', ])
    return dict(zip(day_payoff_feature_names, day_payoff_feature_values))


def get_app_prod_payoff_features(history_merge_installment,
                                 payoff_type='payoff',
                                 day_list=[1, 3, 7, 15, 30, 60, 90, 180, 'all'],
                                 records_list=[1, 3, 7, 15, 30],
                                 current_apply_time=None,
                                 current_acq_channel=None,
                                 current_product_code=None,
                                 feature_type='all'):
    day_payoff_feature_names = []
    day_payoff_feature_values = []
    history_payoff_installment = history_merge_installment[
        history_merge_installment.bill_category.str.contains(payoff_type)].copy()  # 筛选符合还清条件的数据

    if feature_type == 'all':
        history_payoff_installment = history_payoff_installment.copy()
    elif 'app' in feature_type:
        history_payoff_installment = history_payoff_installment[history_payoff_installment.app_type == feature_type]
    elif 'product' in feature_type:
        history_payoff_installment = history_payoff_installment[history_payoff_installment.product_type == feature_type]
    history_payoff_installment['payoff_inter'] = (
            pd.to_datetime(current_apply_time) - pd.to_datetime(history_payoff_installment.update_time)).dt.days
    history_payoff_installment['payoff_sort'] = history_payoff_installment.groupby(['user_id'])['update_time'].rank(
        method='first', ascending=True)  # 还清排序, 正序
    history_payoff_installment['payoff_sort_reverse'] = history_payoff_installment.groupby(['user_id'])[
        'update_time'].rank(method='first', ascending=False)  # 还清排序 倒序

    if len(history_payoff_installment) > 0:  # 如果有还清单
        first_payoff_order_app = \
            history_payoff_installment[history_payoff_installment.payoff_sort == 1].acq_channel.values[0]  # 第一笔结清APP
        first_payoff_order_prod = \
            history_payoff_installment[history_payoff_installment.payoff_sort == 1].product_code.values[
                0]  # 第一笔结清product
        if_first_payoff_order_app = 0  # 第一笔结清APP是否与本次申请的APP一致
        if_first_payoff_order_prod = 0  # 上一笔结清prod是否与本次申请的prod一致
        if first_payoff_order_app == current_acq_channel:
            if_first_payoff_order_app = 1
        if first_payoff_order_prod == current_product_code:
            if_first_payoff_order_prod = 1

        last_payoff_order_app = \
            history_payoff_installment[history_payoff_installment.payoff_sort_reverse == 1].acq_channel.values[
                0]  # 上一笔结清APP
        last_payoff_order_prod = \
            history_payoff_installment[history_payoff_installment.payoff_sort_reverse == 1].product_code.values[
                0]  # 上一笔结清product
        if_last_payoff_order_app = 0  # 上一笔结清APP是否与本次申请的APP一致
        if_last_payoff_order_prod = 0  # 上一笔结清prod是否与本次申请的prod一致
        if last_payoff_order_app == current_acq_channel:
            if_last_payoff_order_app = 1
        if last_payoff_order_prod == current_product_code:
            if_last_payoff_order_prod = 1

        app_payoff_df = history_payoff_installment.groupby('acq_channel').agg(
            payoff_cnt=('app_order_id', 'count')).reset_index()
        prod_payoff_df = history_payoff_installment.groupby('product_code').agg(
            payoff_cnt=('app_order_id', 'count')).reset_index()

        app_payoff_cnt = len(app_payoff_df)  # 有结清订单的app数
        app_payoff_b23_cnt = len(
            app_payoff_df[(app_payoff_df.payoff_cnt >= 2) & (app_payoff_df.payoff_cnt <= 3)])  # 结清订单 2-3 的APP数
        app_payoff_b35_cnt = len(
            app_payoff_df[(app_payoff_df.payoff_cnt >= 3) & (app_payoff_df.payoff_cnt <= 5)])  # 结清订单 3-5 的APP数
        app_payoff_ge5_cnt = len(app_payoff_df[(app_payoff_df.payoff_cnt >= 5)])  # 结清订单>=5的APP数

        prod_payoff_cnt = len(prod_payoff_df)  # 有结清订单的产品数
        prod_payoff_b23_cnt = len(
            prod_payoff_df[(prod_payoff_df.payoff_cnt >= 2) & (prod_payoff_df.payoff_cnt <= 3)])  # 结清订单 2-3 的产品数
        prod_payoff_b35_cnt = len(
            prod_payoff_df[(prod_payoff_df.payoff_cnt >= 3) & (prod_payoff_df.payoff_cnt <= 5)])  # 结清订单 3-5 的产品数
        prod_payoff_ge5_cnt = len(prod_payoff_df[(prod_payoff_df.payoff_cnt >= 5)])  # 结清订单>=5的产品数

        self_app_payoff_cnt = len(history_payoff_installment[
                                      history_payoff_installment.acq_channel == current_acq_channel])  # 截止到当前时间，本APP结清笔数
        self_prod_payoff_cnt = len(history_payoff_installment[
                                       history_payoff_installment.product_code == current_product_code])  # 截止到当前时间，本产品结清笔数

        self_app_payoff_amt_sum = history_payoff_installment[
            history_payoff_installment.acq_channel == current_acq_channel].repaid_amt_sum.sum()  # 截止到当前时间，本APP结清金额和
        self_prod_payoff_amt_sum = history_payoff_installment[
            history_payoff_installment.product_code == current_product_code].repaid_amt_sum.sum()  # 截止到当前时间，本产品结清金额和

    else:
        if_first_payoff_order_app = -999
        if_first_payoff_order_prod = -999
        if_last_payoff_order_app = -999
        if_last_payoff_order_prod = -999
        app_payoff_cnt = -999
        app_payoff_b23_cnt = -999
        app_payoff_b35_cnt = -999
        app_payoff_ge5_cnt = -999
        prod_payoff_cnt = -999
        prod_payoff_b23_cnt = -999
        prod_payoff_b35_cnt = -999
        prod_payoff_ge5_cnt = -999
        self_app_payoff_cnt = -999
        self_prod_payoff_cnt = -999
        self_app_payoff_amt_sum = -999
        self_prod_payoff_amt_sum = -999

    day_payoff_feature_values.extend([if_first_payoff_order_app,
                                      if_first_payoff_order_prod,
                                      if_last_payoff_order_app,
                                      if_last_payoff_order_prod,
                                      app_payoff_cnt,
                                      app_payoff_b23_cnt,
                                      app_payoff_b35_cnt,
                                      app_payoff_ge5_cnt,
                                      prod_payoff_cnt,
                                      prod_payoff_b23_cnt,
                                      prod_payoff_b35_cnt,
                                      prod_payoff_ge5_cnt,
                                      self_app_payoff_cnt,
                                      self_prod_payoff_cnt,
                                      self_app_payoff_amt_sum,
                                      self_prod_payoff_amt_sum, ])
    day_payoff_feature_names.extend([f'{feature_type}_{payoff_type}_bill_if_first_payoff_order_app',
                                     f'{feature_type}_{payoff_type}_bill_if_first_payoff_order_prod',
                                     f'{feature_type}_{payoff_type}_bill_if_last_payoff_order_app',
                                     f'{feature_type}_{payoff_type}_bill_if_last_payoff_order_prod',
                                     f'{feature_type}_{payoff_type}_bill_app_payoff_cnt',
                                     f'{feature_type}_{payoff_type}_bill_app_payoff_b23_cnt',
                                     f'{feature_type}_{payoff_type}_bill_app_payoff_b35_cnt',
                                     f'{feature_type}_{payoff_type}_bill_app_payoff_ge5_cnt',
                                     f'{feature_type}_{payoff_type}_bill_prod_payoff_cnt',
                                     f'{feature_type}_{payoff_type}_bill_prod_payoff_b23_cnt',
                                     f'{feature_type}_{payoff_type}_bill_prod_payoff_b35_cnt',
                                     f'{feature_type}_{payoff_type}_bill_prod_payoff_ge5_cnt',
                                     f'{feature_type}_{payoff_type}_bill_self_app_payoff_cnt',
                                     f'{feature_type}_{payoff_type}_bill_self_prod_payoff_cnt',
                                     f'{feature_type}_{payoff_type}_bill_self_app_payoff_amt_sum',
                                     f'{feature_type}_{payoff_type}_bill_self_prod_payoff_amt_sum', ])

    for day in day_list:
        if day == 'all':
            history_payoff_installment_tmp = history_payoff_installment.copy()  # 最近N天的申请数据
        else:
            history_payoff_installment_tmp = history_payoff_installment[
                history_payoff_installment.payoff_inter <= day].copy()
        payoff_app_cnt_nd = history_payoff_installment_tmp.acq_channel.nunique()  # 最近N天结清APP个数
        payoff_prod_cnt_nd = history_payoff_installment_tmp.product_code.nunique()  # 最近N天结清产品个数
        day_payoff_feature_values.extend([payoff_app_cnt_nd, payoff_prod_cnt_nd])
        day_payoff_feature_names.extend(
            [f'{feature_type}_bill_payoff_app_cnt_{day}d', f'{feature_type}_bill_payoff_prod_cnt_{day}d'])

    history_payoff_installment['payoff_sort_reverse'] = history_payoff_installment.groupby(['user_id'])[
        'update_time'].rank(method='first', ascending=False)  # 还清排序 倒序
    for nr in records_list:
        payoff_app_cnt_nr = history_payoff_installment[
            history_payoff_installment.payoff_sort_reverse <= nr].acq_channel.nunique()  # 最近N笔结清APP个数
        payoff_prod_cnt_nr = history_payoff_installment[
            history_payoff_installment.payoff_sort_reverse <= nr].product_code.nunique()  # 最近N笔结清产品个数
        day_payoff_feature_values.extend([payoff_app_cnt_nr, payoff_prod_cnt_nr])
        day_payoff_feature_names.extend(
            [f'{feature_type}_bill_payoff_app_cnt_{nr}r', f'{feature_type}_bill_payoff_prod_cnt_{nr}r'])

    return dict(zip(day_payoff_feature_names, day_payoff_feature_values))


def get_agg_day_features(history_merge_installment,
                         history_order_data,
                         payoff_type='payoff',
                         day_list=[1, 3, 7, 15, 30, 60, 90, 180, 'all'],
                         current_apply_time=None,
                         feature_type='all'):
    import math
    import numpy as np
    from datetime import datetime
    day_agg_payoff_feature_names = []
    day_agg_payoff_feature_values = []

    history_payoff_installment = history_merge_installment[
        history_merge_installment.bill_category.str.contains(payoff_type)].copy()  # 筛选符合还清条件的数据

    if feature_type == 'all':
        history_payoff_installment = history_payoff_installment.copy()
    elif 'app' in feature_type:
        history_payoff_installment = history_payoff_installment[history_payoff_installment.app_type == feature_type]
    elif 'product' in feature_type:
        history_payoff_installment = history_payoff_installment[history_payoff_installment.product_type == feature_type]

    history_payoff_installment['payoff_day'] = history_payoff_installment.update_time.apply(lambda x: x[:10])
    history_payoff_installment['payoff_sort'] = history_payoff_installment.groupby(['user_id'])['update_time'].rank(
        method='first', ascending=True)  # 还清排序, 正序
    history_payoff_installment['payoff_sort_reverse'] = history_payoff_installment.groupby(['user_id'])[
        'update_time'].rank(method='first', ascending=False)  # 还清排序 倒序
    payoff_day_df = history_payoff_installment.groupby(['payoff_day']).agg(
        payoff_max_time=('update_time', 'max')).reset_index()
    all_payoff_time = sorted(payoff_day_df.payoff_max_time.unique())
    # 计算申请时间差
    if len(all_payoff_time) > 0:
        if len(all_payoff_time) > 1:
            date_objects = [datetime.strptime(date, '%Y-%m-%d %H:%M:%S') for date in all_payoff_time]
            intervals = [(date_objects[i + 1] - date_objects[i]).days for i in range(len(date_objects) - 1)]
            max_iter = (date_objects[-1] - date_objects[0]).days
            payoff_day_contact_density = fea_div_v2(math.sqrt(sum([math.pow(1, 2) for i in intervals])),
                                                    max_iter)  # 按天聚合的联系密度
        else:
            payoff_day_contact_density = -999

        apply_time_diff = []
        for i in range(len(all_payoff_time)):
            if i != len(all_payoff_time) - 1:
                next_order_time = history_order_data[
                    history_order_data.apply_time > all_payoff_time[i]].apply_time.min()
                if str(next_order_time) != 'nan':
                    apply_time_diff.append(get_days_inter(next_order_time, all_payoff_time[i]))
            else:
                apply_time_diff.append(get_days_inter(current_apply_time, all_payoff_time[i]))
        apply_time_diff_max = max(apply_time_diff)  # 结清后，距离下一次申请订单的时间差的max
        apply_time_diff_min = min(apply_time_diff)  # 结清后，距离下一次申请订单的时间差的min
        apply_time_diff_avg = np.mean(apply_time_diff)  # 结清后，距离下一次申请订单的时间差的mean
        apply_time_diff_std = np.std(apply_time_diff)  # 结清后，距离下一次申请订单的时间差的std
    else:
        apply_time_diff_max = -999
        apply_time_diff_min = -999
        apply_time_diff_avg = -999
        apply_time_diff_std = -999
        payoff_day_contact_density = -999

    if len(all_payoff_time) > 0:
        apply_time_diff = []
        for i in range(len(all_payoff_time)):
            if i != len(all_payoff_time) - 1:
                next_order_time = history_order_data[(history_order_data.apply_time > all_payoff_time[i]) & (
                        history_order_data.status == 21)].apply_time.min()
                if str(next_order_time) != 'nan':
                    apply_time_diff.append(get_days_inter(next_order_time, all_payoff_time[i]))
            else:
                apply_time_diff.append(get_days_inter(current_apply_time, all_payoff_time[i]))
        apply_pass_time_diff_max = max(apply_time_diff)  # 结清后，距离下一次放款订单的时间差的max
        apply_pass_time_diff_min = min(apply_time_diff)  # 结清后，距离下一次放款订单的时间差的min
        apply_pass_time_diff_avg = np.mean(apply_time_diff)  # 结清后，距离下一次放款订单的时间差的mean
        apply_pass_time_diff_std = np.std(apply_time_diff)  # 结清后，距离下一次放款订单的时间差的std
    else:
        apply_pass_time_diff_max = -999
        apply_pass_time_diff_min = -999
        apply_pass_time_diff_avg = -999
        apply_pass_time_diff_std = -999
    # 相邻结清订单金额差特征
    if len(history_payoff_installment) > 1:
        adjacent_installment_amt = history_payoff_installment.sort_values(by='payoff_sort').installment_amount.tolist()
        adjacent_installment_amt_diff = [adjacent_installment_amt[i + 1] - adjacent_installment_amt[i] for i in
                                         range(len(adjacent_installment_amt) - 1)]
        adjacent_installment_amt_diff_max = max(adjacent_installment_amt_diff)  # 相邻结清订单的 金额的差的最大值
        adjacent_installment_amt_diff_min = min(adjacent_installment_amt_diff)  # 相邻结清订单的 金额的差的最小值
        adjacent_installment_amt_diff_avg = np.mean(adjacent_installment_amt_diff)  # 相邻结清订单的 金额的差的平均值
        adjacent_installment_amt_diff_std = np.std(adjacent_installment_amt_diff)  # 相邻结清订单的 金额的差的标准差

        adjacent_installment_paid_amt = history_payoff_installment.sort_values(by='payoff_sort').repaid_amt_sum.tolist()
        adjacent_installment_payoff_time = history_payoff_installment.sort_values(by='payoff_sort').update_time.tolist()

        adjacent_installment_low_paid_amt = sum([1 for i in range(len(adjacent_installment_paid_amt) - 1) if
                                             adjacent_installment_paid_amt[i + 1] < adjacent_installment_paid_amt[
                                                 i]])  # 比上一笔结清订单金额低的 结清订单数
        adjacent_installment_firts_low_before_days = -999
        for i in range(len(adjacent_installment_paid_amt) - 1):
            if adjacent_installment_paid_amt[i + 1] < adjacent_installment_paid_amt[i]:
                adjacent_installment_firts_low_before_days = get_days_inter(current_apply_time,
                                                                            adjacent_installment_payoff_time[i + 1])
                break
        adjacent_installment_firts_low_before_days_rate = -999
        if adjacent_installment_firts_low_before_days != -999:
            first_payoff_current_days = get_days_inter(current_apply_time, adjacent_installment_payoff_time[0])
            adjacent_installment_firts_low_before_days_rate = fea_div_v2(adjacent_installment_firts_low_before_days,
                                                                         first_payoff_current_days)
    else:

        adjacent_installment_amt_diff_max = -999
        adjacent_installment_amt_diff_min = -999
        adjacent_installment_amt_diff_avg = -999
        adjacent_installment_amt_diff_std = -999
        adjacent_installment_low_paid_amt = -999
        adjacent_installment_firts_low_before_days = -999
        adjacent_installment_firts_low_before_days_rate = -999
    day_agg_payoff_feature_values.extend([apply_time_diff_max,
                                          apply_time_diff_min,
                                          apply_time_diff_avg,
                                          apply_time_diff_min,
                                          apply_pass_time_diff_max,
                                          apply_pass_time_diff_min,
                                          apply_pass_time_diff_avg,
                                          apply_pass_time_diff_min,
                                          adjacent_installment_amt_diff_max,
                                          adjacent_installment_amt_diff_min,
                                          adjacent_installment_amt_diff_avg,
                                          adjacent_installment_amt_diff_std,
                                          adjacent_installment_low_paid_amt,
                                          adjacent_installment_firts_low_before_days,
                                          adjacent_installment_firts_low_before_days_rate,
                                          payoff_day_contact_density])
    day_agg_payoff_feature_names.extend([f'{feature_type}_{payoff_type}_apply_time_diff_max',
                                         f'{feature_type}_{payoff_type}_apply_time_diff_min',
                                         f'{feature_type}_{payoff_type}_apply_time_diff_avg',
                                         f'{feature_type}_{payoff_type}_apply_time_diff_min',
                                         f'{feature_type}_{payoff_type}_apply_pass_time_diff_max',
                                         f'{feature_type}_{payoff_type}_apply_pass_time_diff_min',
                                         f'{feature_type}_{payoff_type}_apply_pass_time_diff_avg',
                                         f'{feature_type}_{payoff_type}_apply_pass_time_diff_min',
                                         f'{feature_type}_{payoff_type}_adjacent_installment_amt_diff_max',
                                         f'{feature_type}_{payoff_type}_adjacent_installment_amt_diff_min',
                                         f'{feature_type}_{payoff_type}_adjacent_installment_amt_diff_avg',
                                         f'{feature_type}_{payoff_type}_adjacent_installment_amt_diff_std',
                                         f'{feature_type}_{payoff_type}_adjacent_installment_low_paid_amt',
                                         f'{feature_type}_{payoff_type}_adjacent_installment_firts_low_before_days',
                                         f'{feature_type}_{payoff_type}_adjacent_installment_firts_low_before_days_rate',
                                         f'{feature_type}_{payoff_type}_payoff_day_contact_density'])
    return dict(zip(day_agg_payoff_feature_names, day_agg_payoff_feature_values))


def get_continue_acc_feature(history_merge_installment,
                             payoff_type='payoff',
                             feature_type='all'):
    acc_payoff_feature_values = []
    acc_payoff_feature_names = []
    history_payoff_installment = history_merge_installment[
        history_merge_installment.bill_category.str.contains(payoff_type)].copy()  # 筛选符合还清条件的数据
    if feature_type == 'all':
        history_payoff_installment = history_payoff_installment.copy()
    elif 'app' in feature_type:
        history_payoff_installment = history_payoff_installment[history_payoff_installment.app_type == feature_type]
    elif 'product' in feature_type:
        history_payoff_installment = history_payoff_installment[history_payoff_installment.product_type == feature_type]

    history_payoff_installment['payoff_day'] = history_payoff_installment.update_time.apply(lambda x: x[:10])
    history_payoff_installment['payoff_sort'] = history_payoff_installment.groupby(['user_id'])['update_time'].rank(
        method='first', ascending=True)  # 还清排序, 正序
    history_payoff_installment['payoff_sort_reverse'] = history_payoff_installment.groupby(['user_id'])[
        'update_time'].rank(method='first', ascending=False)  # 还清排序 倒序
    history_payoff_installment['onloan_days'] = history_payoff_installment['ovd_days'] + 7
    history_payoff_installment['onloan_contribution_value'] = history_payoff_installment['onloan_days'] * \
                                                              history_merge_installment['installment_amount']

    # 连续模式，连续提前结清分占比，连续正常结清的占比
    continue_payoff_type = history_payoff_installment.sort_values(by='payoff_sort').bill_category.tolist()
    max_sequences = find_max_consecutive(continue_payoff_type)
    if 'pre_payoff' in list(max_sequences.keys()):
        pre_payoff_len = max_sequences['pre_payoff'][1] - max_sequences['pre_payoff'][0]  # 连续提前还清的最大次数
        pre_payoff_len_rate = fea_div_v2(pre_payoff_len, len(continue_payoff_type))  # 连续提前还清的最大次数占比
    else:
        pre_payoff_len = -999
        pre_payoff_len_rate = -999
    if 'normal_payoff' in list(max_sequences.keys()):
        normal_payoff_len = max_sequences['normal_payoff'][1] - max_sequences['normal_payoff'][0]  # 连续正常还清的最大次数
        normal_payoff_len_rate = fea_div_v2(normal_payoff_len, len(continue_payoff_type))  # 连续正常还清的最大次数占比
    else:
        normal_payoff_len = -999
        normal_payoff_len_rate = -999
    # 所有还清单计算累计在贷贡献值
    acc_onloan_cv = history_payoff_installment.onloan_contribution_value.sum()  # 累计在贷 贡献值（去掉逾期未还订单）
    acc_onloan_cd = history_payoff_installment.onloan_days.sum()  # 累计在贷 天数（去掉逾期未还订单）
    acc_onloan_no_ovd_cv = history_payoff_installment[
        history_payoff_installment.bill_category != 'ovd_payoff'].onloan_contribution_value.sum()  # 累计在贷 贡献值（去掉逾期结清）
    acc_onloan_no_ovd_cd = history_payoff_installment[
        history_payoff_installment.bill_category != 'ovd_payoff'].onloan_days.sum()  # 累计在贷 天数（去掉逾期结清）
    acc_payoff_feature_values.extend([pre_payoff_len,
                                      pre_payoff_len_rate,
                                      normal_payoff_len,
                                      normal_payoff_len_rate,
                                      acc_onloan_cv,
                                      acc_onloan_cd,
                                      acc_onloan_no_ovd_cv,
                                      acc_onloan_no_ovd_cd, ])
    acc_payoff_feature_names.extend([f'{feature_type}_{payoff_type}_pre_payoff_len',
                                     f'{feature_type}_{payoff_type}_pre_payoff_len_rate',
                                     f'{feature_type}_{payoff_type}_normal_payoff_len',
                                     f'{feature_type}_{payoff_type}_normal_payoff_len_rate',
                                     f'{feature_type}_{payoff_type}_acc_onloan_cv',
                                     f'{feature_type}_{payoff_type}_acc_onloan_cd',
                                     f'{feature_type}_{payoff_type}_acc_onloan_no_ovd_cv',
                                     f'{feature_type}_{payoff_type}_acc_onloan_no_ovd_cd'])
    return dict(zip(acc_payoff_feature_names, acc_payoff_feature_values))
